/**
 * @author liangxi
 * @since 2024/3/20
 */

#include <sstream>
#include "../Header/Logger.h"
#include "../Header/Behavior/Write/Impl/WriteToConsole.h"
#include "../Header/Behavior/Write/Impl/WriteToFile.h"
#include "../Header/Platform/Helper/LogHelper.h"


void Logger::asyncLog(std::string_view content, Log::LogLevel level, Log::Output out, std::string_view path,
                      const std::source_location &location) {
    //异步实现 将日志内容和输出方式传递给createLog方法，返回一个Log对象 将Log放入队列中
    std::unique_lock<std::mutex> lock(mMutex);
    mLogs.push_back(createLog(content, level, out, path, location));
    //mCond.notify_one();
}

void Logger::syncLog(std::string_view content, Log::LogLevel level, Log::Output out, std::string_view path,
                     const std::source_location &location) {
    //同步实现 直接调用write方法
    std::unique_lock<std::mutex> lock(mMutex);
    Log log = createLog(content, level, out, path, location);
    setWriteBehavior(out);
    writeBehavior->write(log.getMContent(), log.getMFileName(), log.getMPath());
}

void Logger::setWriteBehavior(Log::Output out) {
    switch (out) {
        case Log::Output::Console:
            writeBehavior = std::make_unique<WriteToConsole>();
            break;
        case Log::Output::File:
            writeBehavior = std::make_unique<WriteToFile>();
            break;
        default:
            writeBehavior = nullptr;
            break;
    }
}

Log Logger::createLog(std::string_view content, Log::LogLevel level, Log::Output out, std::string_view path,
                      const std::source_location &location) {
    auto time = LogHelper::getLocalTime();

    std::stringstream ss;
    ss << time.getYear() << "/" << time.getMonth() << "/" << time.getDay() << " "
       << time.getHour() << ":" << time.getMinute() << ":" << time.getSecond();

    std::string timeStr{ss.str()};
    std::string msg = timeStr + "[" + location.file_name() + ":" +
                      std::to_string(location.line()) + ":" + Log::levelToString(level) + "]:";
    msg += content;

    ss.clear();
    ss.str("");

    ss << time.getYear() << "_" << time.getMonth() << "_" << time.getDay() << ".log";
    std::string fileName{ss.str()};

    std::string dir{path};

    return Log{out, msg, fileName, dir};
}

void Logger::threadExec() {
    while (mIsRunning) {
        //先判断是否有日志需要输出
        if (mLogs.empty())
            continue;

        std::unique_lock<std::mutex> lock(mMutex);
        //mCond.wait(lock, [this] { return !mLogs.empty(); });
        Log log = mLogs.front();
        mLogs.pop_front();
        setWriteBehavior(log.getMOutput());
        writeBehavior->write(log.getMContent(), log.getMFileName(), log.getMPath());
    }

#if WIN32
    syncLog(LogHelper::utf8ToGbk("日志输出完毕 日志线程停止..."), Log::LogLevel::Info, Log::Output::Console);
#else
    syncLog("日志输出完毕 日志线程停止...", Log::LogLevel::Info, Log::Output::Console);
#endif
}